#include "TriangleMesh.h"
#include "Esfera.h"
#include <QDebug>

const Objeto_3D* TriangleMesh::Intercepta( Raio r_vis, float* ret)const
{
    if(!bb.Intercepta(r_vis))
     {
         *ret = -1.0;
         return this;
     }

     return kdt.intecepta(r_vis, ret);
}

TriangleMesh::TriangleMesh(PlyParser::iterator_st bit, PlyParser::iterator_st eit, int ind, float para[9] ): Objeto_3D(ind)
{
    float xmin, xmax, ymin, ymax, zmin, zmax;
    float x,y,z;

    Ponto_3D v1,v2,v3;

    Triangulo *t;
    Triangulo tmp(0, Ponto_3D(), Ponto_3D(), Ponto_3D());

    if(bit != eit)
    {
        tmp = Triangulo(bit.getTriangulo());

        x = tmp.getVertice1().X() * para[0] + para[3];
        y = tmp.getVertice1().Y() * para[1] + para[4];
        z = tmp.getVertice1().Z() * para[2] + para[5];

        v1 = Ponto_3D(x,y,z);

        x = tmp.getVertice2().X() * para[0] + para[3];
        y = tmp.getVertice2().Y() * para[1] + para[4];
        z = tmp.getVertice2().Z() * para[2] + para[5];

        v2 = Ponto_3D(x,y,z);

        x = tmp.getVertice3().X() * para[0] + para[3];
        y = tmp.getVertice3().Y() * para[1] + para[4];
        z = tmp.getVertice3().Z() * para[2] + para[5];

        v3 = Ponto_3D(x,y,z);


        t = new Triangulo(tmp.Indice_textura(), v1, v2, v3);

        xmin = t->getVertice1().X() ;
        xmax = t->getVertice1().X();
        ymin = t->getVertice1().Y();
        ymax = t->getVertice1().Y();
        zmin = t->getVertice1().Z();
        zmax = t->getVertice1().Z();

        xmin = MINI(xmin, t->getVertice2().X());
        xmin = MINI(xmin, t->getVertice3().X());
        xmax = MAXI(xmax, t->getVertice2().X());
        xmax = MAXI(xmax, t->getVertice3().X());

        ymin = MINI(ymin, t->getVertice2().Y());
        ymin = MINI(ymin, t->getVertice3().Y());
        ymax = MAXI(ymax, t->getVertice2().Y());
        ymax = MAXI(ymax, t->getVertice3().Y());

        zmin = MINI(zmin, t->getVertice2().Z());
        zmin = MINI(zmin, t->getVertice3().Z());
        zmax = MAXI(zmax, t->getVertice2().Z());
        zmax = MAXI(zmax, t->getVertice3().Z());

        t->setIndiceTextura(ind);
        t->refazArestas();

        mesh.push_back(t);
    }

    for(++bit; bit != eit; ++bit)
    {
        tmp = Triangulo(bit.getTriangulo());

        x = tmp.getVertice1().X() * para[0] + para[3];
        y = tmp.getVertice1().Y() * para[1] + para[4];
        z = tmp.getVertice1().Z() * para[2] + para[5];

        v1 = Ponto_3D(x,y,z);

        x = tmp.getVertice2().X() * para[0] + para[3];
        y = tmp.getVertice2().Y() * para[1] + para[4];
        z = tmp.getVertice2().Z() * para[2] + para[5];

        v2 = Ponto_3D(x,y,z);

        x = tmp.getVertice3().X() * para[0] + para[3];
        y = tmp.getVertice3().Y() * para[1] + para[4];
        z = tmp.getVertice3().Z() * para[2] + para[5];

        v3 = Ponto_3D(x,y,z);

        t = new Triangulo(tmp.Indice_textura(), v1, v2, v3);

        xmin = MINI(xmin, t->getVertice1().X());
        xmin = MINI(xmin, t->getVertice2().X());
        xmin = MINI(xmin, t->getVertice3().X());
        xmax = MAXI(xmax, t->getVertice1().X());
        xmax = MAXI(xmax, t->getVertice2().X());
        xmax = MAXI(xmax, t->getVertice3().X());

        ymin = MINI(ymin, t->getVertice1().Y());
        ymin = MINI(ymin, t->getVertice2().Y());
        ymin = MINI(ymin, t->getVertice3().Y());
        ymax = MAXI(ymax, t->getVertice1().Y());
        ymax = MAXI(ymax, t->getVertice2().Y());
        ymax = MAXI(ymax, t->getVertice3().Y());

        zmin = MINI(zmin, t->getVertice1().Z());
        zmin = MINI(zmin, t->getVertice2().Z());
        zmin = MINI(zmin, t->getVertice3().Z());
        zmax = MAXI(zmax, t->getVertice1().Z());
        zmax = MAXI(zmax, t->getVertice2().Z());
        zmax = MAXI(zmax, t->getVertice3().Z());

        t->setIndiceTextura(ind);

        t->refazArestas();

        mesh.push_back(t);
    }

    setCentro(Ponto_3D((xmin+xmax)/2, (ymin+ymax)/2, (zmin+zmax)/2));
    setRaio( centro.distancia(Ponto_3D(xmin,ymin,zmin)));

    for(int i = 0; i < mesh.size(); ++i)
    {
        mesh[i]->setCentro(this->getCentro());
        mesh[i]->setRaio(this->getRaio());
    }

    bb = BoundingBox(Vetor_3D(xmin,ymin,zmin) , Vetor_3D(xmax, ymax, zmax));

    calculaCoordenadasTextura();

    kdt.constroi(mesh, bb);
}
void TriangleMesh::calculaCoordenadasTextura()
{
    float phi, theta;
    TexturePoint tx;
    Ponto_3D projecao;
    Vetor_3D proj;

    for(int i=0; i < mesh.size(); ++i)
    {
        for(int j = 0; j < 3; ++j)
        {
            if(j == 0)
                projecao = mesh[i]->getVertice1();
            else if(j == 1)
                projecao = mesh[i]->getVertice2();
            else
                projecao = mesh[i]->getVertice2();

            proj = projecao - centro;
            proj.normaliza();

            phi  = acosf(proj.Z());
            theta = acosf(proj.X()/sin(phi));

            tx.U(phi/M_PI);
            tx.V((theta)/M_PI);

            if(j == 0)
                mesh[i]->setTexturePoint1(tx);
            else if(j == 1)
                mesh[i]->setTexturePoint2(tx);
            else mesh[i]->setTexturePoint3(tx);
        }
    }
}
